如何从0打造像dubbo一样的生产级RPC?(功能介绍篇)
一、背景
互联网应用如电商、游戏、社交、短视频等应用在移动互联网时代经历快速发展,头部产品如微信、淘宝、抖音、微博等达到亿级甚至十亿级用户活跃, 公司的研发人员也从几百、几千到几万不等, 为适应这种业务变化互联网应用架构在过去十余年内早已从早期单体架构过渡到微服务架构为主,关于单体架构、微服务架构的利弊以及在不同体量、业务场景如何选择业内已有大量文章发表篇幅有限本文就不另作表述。在这个背景下头部产品的微服务应用规模到达十万级应用、日调用量到达万亿级,部分中等应用也在千级服务、百亿甚至千亿级日访问。要应对如此高并发、大流量、高可用性的系统架构要求,打造一款高性能、强稳定、功能丰富的微服务通讯框架对业务的快速发展及稳定运行至关重要,行业内应用架构如何构建微服务框架大体分为三种路径:
头部或二线大厂的完全自研:一线大厂如阿里系、头条系、美团、腾讯、百度等都有完整的自研微服务解决方案,二线厂如58同城、唯品会、微博等研发团队体量较大公司也都采用自研方式。(备注:区分一二线厂很容易引起争议,在这里还是先按公司市值来判定)
基于开源解决方案
头部大厂开源方案(Java生态为例):如阿里的dubbo、支付宝的sofa、美团的octo等等
基于springcloud 社区解决方案
其它语言如Go语言生态(头条的KiteX、腾讯的北极星等),C/C++语言(百度的brpc)等
基于开源方案的二次开发
部分中厂采用基于dubbo二次开发方式,使用dubbo核心功能,部分与技术体系内部系统功能采用二次开发解决;
也有不少公司基于springcloud体系的二次开发路线
其它语言二次开发
完全自研 | 开源方案 | 二次开发 | |
技术复杂度 | 非常高 | 低(以使用掌握为主) | 中等 |
技术可控度 | 新的功能特性、bug修复、版本规划等自主控制,可快速响应业务需要 | 遇到问题需要提交社区 能否支持以及修复时间不确定 | 1. 核心功能二次开发掌控投入成本大 2.如只解决周边适配运维相关系统,总体开发量尚可 |
人力投入 | 一线大厂RPC 投入在10~几十人不等 二线厂:3~10人不等 | 不需要独立的infra开发人员 | 看修改复杂度 几人到10人不等 |
架构风险 | 因功能特性较多,整体架构运行稳定需要较长时间内部场景验证 | 开源组件的未知风险,如springcloud体系涉及大量组件 | 核心架构风险能否解决需要看团队投入 重点在周边小功能bug修复以及定制 |
以上为三种不同路径在技术复杂度、可控度、人力投入、架构风险等方面的对比,三种路径业内都存在具体怎么选需要根据各公司具体人员规模、技术储备、改造成本、长期技术目标等实际情况来综合考虑。另外关于是否要在公司技术体系内推自研RPC解决方案,有以下维度个人经验可供参考:
体量较大的公司一般是必选项,如能自研对公司核心技术把控度有较大掌握,避免“卡脖子”问题
直接应用开源方案或者二次开发成本较高的场景,部分公司RPC可能需要适配现有的运维系统如发布系统、监控体系、配置体系等等,部分开源方案代码量级已经很大了, 如dubbo 3.0已经到达30w+行数级别
RPC能力需深度定制,对比开源方案的“大而全”,想在公司内部实现“小而精”解决方案
笔者在过去近十年的工作中亲历多家互联网公司多款RPC框架的打造以及应对业务挑战不断架构迭代升级,对业内多款开源rpc 如dubbo、sofa、octo等都有源码级了解,甚至近期在某司又从0到1 主导完成过生产级RPC的研发以及上线推广覆盖,对RPC核心功能、实现路径、工程级实现、人力投入、架构风险&把控、人员培养有一定的经验积累,书写本文希望能把相关经历做个分享,也欢迎大家对其中的问题来找我交流反馈。整个RPC系列计划分功能介绍篇、工程实现篇、生产实践篇三个子系列文章来介绍,本文为系列开头上篇功能介绍。
二、RPC核心功能概览
以上为我根据行业内主要开源RPC框架的功能特性、以及个人多年研发架构经验进行汇总,可能有遗漏待完善补充;
下面分别对各个模块能力进行介绍:
基础能力
1. RPC核心通信能力:
需要解决通信方式如接口、IDL定义,以及通信定义如何序列化编解码、传输、调用等关键路径
以一个非常简单的Java Hello 接口进行举例:
Java 接口定义:
public interface HelloService {String sayHello(String message);
String sayBye(String message) throws Exception;
}
Thrift IDL定义:
namespace java com.xx.test.thrift.apiservice HelloService
{
string sayHello(1:string username)
string sayBye(1:string username)
}
在进程如要实现接口调用非常简单,一旦需要跨进程调用就会涉及RPC请求构建封装、序列化、网络传输、反序列化、服务端处理等多个环节,具体细节计划在下一篇工程实现篇进行讲解。
2. 高性能:
大体量互联网应用中服务日调用量在百亿、千亿甚至万亿级别,保证框架级别通讯耗时p99 需要1ms左右,单POD 如4核 2GJVM 进程能支持10w~15w以上qps。
同1 核心通信能力介绍 rpc请求会经过如 接口动态代理、RPC request 构建、客户端filter处理、客户端编码、网络传输、服务端解码、线程池处理、服务端filter,trace、监控上报等多个环节,总体执行开销端到端控制在1~2ms内是打造高性能框架关键点。
3. 高可用:
微服务体系中关键依赖如注册中心的可用性至关重要,设想下假如服务注册中心不可用获取不到服务节点数据而调用侧又没有缓存,严重情况会引发应用整体不可用故障风险。
但该场景为强AP: 对数据的可用性要求很高,对节点数据不一致性要求不太高,甚至异常情况可允许部分节点错误(例如节点上下线未通知调用侧失败等)
4. 服务注册发现:
注册发现为微服务架构核心能力,服务提供方需注册到特定的注册中心,且服务消费方能及时发现下游服务节点变化;
注册中心的实现业内有多种方式, 常见的底层注册元数据存储有:
zookeeper
etcd
redis
mysql
nacos
...
对注册中心有主要核心能力:
1. 对节点或应用元数据的存储(可以树状 或KV方式进行存储)
2. 元数据变更的调用侧即时通知
3. 整体可用性保障(需支持较大量级的元数据拉取,订阅)
关于不同注册中心的选型以及如何保障实现很高的AP,计划在生产实践篇进行重点介绍。
5. 调用方式:
为满足不同业务调用场景需提供例如oneway、async(异步)、sync(同步)甚至stream 等多种业务请求调用方式;
6. 容错:
解决如调用失败集群内处理方式,常见有FailFast(快速失败)、FailOver(重试)、FailBack(后台自动调用恢复)等
服务治理能力
1. 限流
解决服务提供方对上游流量过高进行qps限制能力,如大促时流量爆发,秒杀业务流量高峰等,常见的限流粒度可以基于IP、上游服务标识、调用接口或参数等粒度;
2. 熔断降级
解决服务调用方对下游过载情况快速切断请求并返回特定的降级逻辑从而不影响核心业务;常见熔断的判断指标有包括线程数、信号量、错误率,超时数等等;
3. 其它
其它如对服务内调用强弱依赖度分析、客户端自适应容错等能力;
流量管控
对集群节点内流量的转发和分配,主要包括流量路由以及负载均衡
1. 流量路由
支持请求按条件、标签、脚本等自动路由能力,实现类似服务分组、版本分组调用,实例tag分组,按机房、地域等流量分配能力;
基于以上路由能力可以构建相关服务治理场景如流量分组、机房调度、灰度、泳道能力等;
2. 负载均衡
在流量路由的基础上完成对该组内节点的流量分配,常见的LB算法有随机、随机+权重,一致性Hash、roundrobin、最小连接等等;
其它能力
对微服务治理或实际生产运行较大需求的一些功能点进行简单介绍:
1. 优雅上下线:
避免上下线时对流量的影响,实现进程发布或下线时上游调用无感或报错极少;
2. 服务预热:
对新启动节点由于Java 服务启动前期响应速度略慢,需要进行一定周期放量,避免前几秒调用较多超时;
3. 延迟注册:
应用启动可能需要加载较多资源或执行任务,可设置相关资源完成后进行延迟注册,避免服务还未就绪请求打过来流量受损;
4. 线程池隔离:
对相同的provider服务 进行线程池单独分配,确保部分接口异常不占满全部资源影响整个应用;
5. 泛化调用:
支持不需要提供具体的接口通用调用能力,类似的应用场景有接口测试、压力测试、服务编排等方向;
应用可观测性
1. 监控:
采集应用核心metric,例如每秒请求数、错误数、超时数、异常数等等(可覆盖应用、接口、方法等统计维度)
2. trace
全链路追踪系统,把请求从API 网关、服务层各层调用节点进行串联, 可用来分析请求过程中服务、资源相关调用情况、调用瓶颈,强弱依赖等;
3. 日志
覆盖应用级相关日志,对访问、超时、内部异常等需要有日志覆盖
健康检测
实例存活或健康度判定,进而进行流量干预
1. 中心化检测:使用集群对现有服务列表实例进行探活检测(主要包括连接检测、心跳包检测、健康指标返回检测)
2. 客户端检测:客户端基于一定的流量访问探测算法进行对调用实例的存活判定,例如sofa实现的AFT算法,该方式的主要优点是不受中心化判定因素干扰(例如网络),按客户端调用视角进行按需摘除故障节点。
微服务管理后台
解决对微服务核心能力管理需求
1. 服务列表查看、实例列表查看,实例隔离灰度等能力
2. 对服务上游调用情况访问
3. 其它如核心指标相关查看
微服务测试平台
对接口定义、接口请求测试、测试用例mock及集成
运维体系集成
1. 集成运维中相关CI\CD系统、CMDB、发布系统、k8s、监控系统等
2. 解决服务交付过程中开发、构建、镜像打包、发布、扩缩容等运维需求
多语言支持
解决技术体系内不同业务多语言调用支持
常见的解决思路有
1. 框架内直接支持类似GRPC、thrift等支持跨语言能力通讯协议,总体对各语言兼容度最好,但该方式实现复杂度略高;
2. 使用轻量级协议:如支持REST 方式,http通道 + json 甚至redis通道+json也是一种可选项。
3. 支持如service mesh等高阶能力;
服务鉴权
1. 解决对微服务调用鉴权需求, 支持如基于访问IP、应用标识、用户密码、证书等多种认证方式
周边生态融合
1. 与其它中间件系统的整合:如API网关的通信协议打通,消息中间件、存储中间件集成等
进阶架构
1. 如业务发展规模较大,需要涉及多机房架构或混合云等技术体系,会出现类似多机房注册中心、机房流量调度等架构进阶需求
2. 业内在应对infra组件如何对业务无感升级,多语言支持等各大公司在容器化的基础上会进行service mesh化,具体实现方式和路径篇幅有限有机会再单独整理。
三、最后
以上对RPC 框架在主要技术实现路径、自研框架的选型参考、核心能力进行概要介绍,下篇会针对RPC 框架工程级实现涉及主要技术模块、模型定义、通讯方式、协议定义、编解码方式等进行展开介绍;由于编写本文时间有限,有错误之处请见谅并请随时联系作者进行勘误。
如对基础架构核心实现、业务架构设计等领域想持续与老杨交流,欢迎关注本文工作号:服务端架构,再次感谢您的支持!